#pragma once
#include <log.h>
#include <memory>
#include <odb/exception.hxx>
#include <vector>
#include <odb/mysql/connection-factory.hxx>
#include <odb/mysql/connection.hxx>
#include <odb/mysql/database.hxx>
#include <odb/query.hxx>
#include <odb/result.hxx>
#include <odb/transaction.hxx>
#include "User.hpp" 
#include "User-odb.hxx"
#include "user.pb.h"

using namespace std;
namespace lyt{


    class UserData{
    private:
        shared_ptr<odb::mysql::database> db;
    public:
        using ptr = std::shared_ptr<UserData>;
        UserData(const shared_ptr<odb::mysql::database>& client)
            :db(client)
        {}
// ============================User表-begin============================

        bool insert_user(const std::string& email,const std::string& avatar,const std::string& username,const std::string& password
                        ,const std::string& version){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                User user(email,avatar,username,password,version);
                db->persist(user);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                transa.rollback();
                errorlog << "ODB异常: " << e.what();
                return false;
            } catch (const std::exception& e) {
                transa.rollback();
                errorlog << "其他异常: " << e.what();
                return false;
            }
        }

        bool query_user(const std::string& em,User& user){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<User>;
                using result = odb::result<User>;
                result res(db->query<User>(query::email == em));
                for(auto it = res.begin();it != res.end();it++){
                    user.email=it->email;
                    user.avatar=it->avatar;
                    user.username=it->username;
                    user.version=it->version;
                }
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                transa.rollback();
                errorlog << "ODB异常: " << e.what();
                return false;
            } catch (const std::exception& e) {
                transa.rollback();
                errorlog << "其他异常: " << e.what();
                return false;
            }
        }

        bool query_user_email(const std::string& em){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<User>;
                using result = odb::result<User>;
                result res(db->query<User>(query::email == em));
                
                bool ret = !res.empty();
                transa.commit();
                return ret;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

        bool query_user_avatar(const std::string& em,std::string& uuid){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<User>;
                using result = odb::result<User>;

                result res(db->query<User>(query::email == em));
                auto it= res.begin();
                uuid = it->avatar;
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }
        bool query_user_password(const std::string& em,std::string& pwd){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<User>;
                using result = odb::result<User>;

                result res(db->query<User>(query::email == em));
                auto it= res.begin();
                pwd = it->password;
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

        // bool query_user_emails(const std::vector<std::string>& em,std::vector<std::vector<std::string>>& info){
        //     odb::transaction transa;
        //     try{
        //         transa.reset(db->begin());
        //         using query = odb::query<User>;
        //         using result = odb::result<User>;

        //         result res = db->query<User>(query::email.in_range(em.begin(), em.end()));

        //         for(auto it = res.begin();it != res.end();it++){
        //             std::vector<std::string> tmp;
        //             tmp.push_back(it->email);
        //             tmp.push_back(it->avatar);
        //             tmp.push_back(it->username);
        //             tmp.push_back(it->password);
        //             tmp.push_back(it->version);
        //             info.push_back(tmp);
        //         }
        //         transa.commit();
        //         return true;
        //     } catch (const odb::exception& e) {
        //         errorlog << "ODB异常: " << e.what();
        //         transa.rollback();
        //         return false;
        //     } catch (const std::exception& e) {
        //         errorlog << "其他异常: " << e.what();
        //         transa.rollback();
        //         return false;
        //     }
        // }

        bool query_user_name(const std::string& email,std::string& name){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<User>;
                using result = odb::result<User>;

                result res(db->query<User>(query::email == email));
                auto it = res.begin();
                name = it->username;
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

        bool exist_username(const std::string& name){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<User>;
                using result = odb::result<User>;

                result res(db->query<User>(query::username == name));
                bool ret = !res.empty();
                transa.commit();
                return ret;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

        bool query_user_version(const std::string& em,std::string& version){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<User>;
                using result = odb::result<User>;

                result res(db->query<User>(query::email == em));
                auto it = res.begin();
                version = it->version;
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }
        // query_userstats_by_idxs函数仅供blog模块的查询userstats使用
        bool query_userstats_by_idxs(const std::unordered_set<std::string>& authors_id
                                    ,std::unordered_map<std::string,user::UserStats>& userstats_map){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<User>;
                using result = odb::result<User>;
                // 将set转化为vector方便后续进行in_range
                std::vector<std::string> ids(authors_id.begin(),authors_id.end());

                auto res = db->query<User>(query::email.in_range(ids.begin(), ids.end()));
                for(auto& user:res){
                    user::UserStats userstats;
                    userstats.set_email(user.email);
                    userstats.set_avatar(user.avatar);
                    userstats.set_name(user.username);
                    userstats_map[user.email] = std::move(userstats);
                }
                
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }
        bool update_user(const User& user){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                // 会根据主键 email 来更新该用户的其他字段
                db->update(user);          
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

        bool update_username(const std::string& email,const std::string& username){
            odb::transaction transa;
            try {
                transa.reset(db->begin());
                
                using query = odb::query<User>;
                using result = odb::result<User>;
                result res(db->query<User>(query::email == email));
                User s = *res.begin();
                s.username = username;
                
                db->update(s);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB更新用户名异常: " << e.what();
                transa.rollback();
                return false; 
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

        bool update_version(const std::string& email,const std::string& version){
            odb::transaction transa;
            try {
                transa.reset(db->begin());
                
                using query = odb::query<User>;
                using result = odb::result<User>;
                result res(db->query<User>(query::email == email));
                User s = *res.begin();
                s.version = version;
                
                db->update(s);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB更新用户名异常: " << e.what();
                transa.rollback();
                return false; 
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

        bool update_avartar(const std::string& email,const std::string& avartar_path){
            odb::transaction transa;
            try {
                transa.reset(db->begin());
                
                using query = odb::query<User>;
                using result = odb::result<User>;
                result res(db->query<User>(query::email == email));
                User s = *res.begin();
                s.avatar = avartar_path;
                
                db->update(s);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB更新用户名异常: " << e.what();
                transa.rollback();
                return false; 
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }
        bool update_password(const std::string& email,const std::string& new_password){
            odb::transaction transa;
            try {
                transa.reset(db->begin());
                
                using query = odb::query<User>;
                using result = odb::result<User>;
                result res(db->query<User>(query::email == email));
                User s = *res.begin();
                s.password = new_password;
                
                db->update(s);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB更新用户名异常: " << e.what();
                transa.rollback();
                return false; 
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

        bool delete_user(const User& user){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<User>;
                using result = odb::result<User>;
                result res(db->query<User>(query::email == user.email));
                auto it = res.begin();
                if(it  == res.end()){
                    return true;
                }
                db->erase(user);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }
// ============================User表-end============================


// ============================UserStatsSummary-begin============================

        bool insert_userstatssummary(const UserStatsSummary& userstatssummary){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                db->persist(userstatssummary);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                transa.rollback();
                errorlog << "ODB异常: " << e.what();
                return false;
            } catch (const std::exception& e) {
                transa.rollback();
                errorlog << "其他异常: " << e.what();
                return false;
            }
        }

        bool query_userstatssummary(const std::string& em,std::vector<int>& info){
            info.clear();
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<UserStatsSummary>;
                using result = odb::result<UserStatsSummary>;

                result res(db->query<UserStatsSummary>(query::email == em));
                for(auto it = res.begin();it != res.end();it++){
                    info.push_back(it->solved_problems);
                    info.push_back(it->attempting_problems);
                    info.push_back(it->published_blogs);
                    info.push_back(it->following);
                    info.push_back(it->followers);
                    info.push_back(it->mutual_friends);
                }
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                transa.rollback();
                errorlog << "ODB异常: " << e.what();
                return false;
            } catch (const std::exception& e) {
                transa.rollback();
                errorlog << "其他异常: " << e.what();
                return false;
            }
        }

        bool delete_userstatssummary(const UserStatsSummary& userstatssummary){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<UserStatsSummary>;
                using result = odb::result<UserStatsSummary>;
                result res(db->query<UserStatsSummary>(query::email == userstatssummary.email));
                auto it = res.begin();
                if(it  == res.end()){
                    return false;
                }
                db->erase(userstatssummary);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

        bool update_userstatssummary(const UserStatsSummary& userstatssummary){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                // 会根据主键 email 来更新该用户的其他字段
                db->update(userstatssummary);          
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }
        bool update_userstatssummary_like(const std::string& email) {
            odb::transaction transa;
            try {
                transa.reset(db->begin());

                using query = odb::query<UserStatsSummary>;
                using result = odb::result<UserStatsSummary>;
                result res(db->query<UserStatsSummary>(query::email == email));

                // 2. 修改 likes 字段
                auto ptr = res.begin();

                ptr->blog_likes_number++;
                // 3. 更新对象到数据库
                db->update(*ptr);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "更新likes失败: " << e.what();
                return false;
            }catch (const std::exception& e) {
                transa.rollback();
                errorlog << "其他异常: " << e.what();
                return false;
            }
        }
        bool delete_userstatssummary_like(const std::string& email) {
            odb::transaction transa;
            try {
                transa.reset(db->begin());

                using query = odb::query<UserStatsSummary>;
                using result = odb::result<UserStatsSummary>;
                result res(db->query<UserStatsSummary>(query::email == email));

                // 2. 修改 likes 字段
                auto ptr = res.begin();

                ptr->blog_likes_number--;
                // 3. 更新对象到数据库
                db->update(*ptr);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "更新likes失败: " << e.what();
                return false;
            }catch (const std::exception& e) {
                transa.rollback();
                errorlog << "其他异常: " << e.what();
                return false;
            }
        }
// ============================UserStatsSummary-end============================


// ============================DefaultAvatar-begin============================

        bool insert_default_avatar(UserDefaultAvatar& avatar_md5){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                db->persist(avatar_md5);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }
        bool query_default_avatar(std::vector<std::string>& ret){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<UserDefaultAvatar>;
                using result = odb::result<UserDefaultAvatar>;
                result res(db->query<UserDefaultAvatar>(query(true)));
                for (auto path : res) {
                    ret.push_back(path.avatar_md5);
                }
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }
// ============================DefaultAvatar-end============================

// ============================UserFollowerInfo-begin============================

        bool insert_user_follow(const std::string& follower,const std::string& following){
            odb::transaction transa;
            try{
                odb::transaction trans(db->begin());
                UserFollowInfo info(follower, following); // 注意构造顺序
                db->persist(info);
                trans.commit();
                return true;
            } catch (const odb::exception& e) {
                transa.rollback();
                errorlog << "ODB异常: " << e.what();
                return false;
            } catch (const std::exception& e) {
                transa.rollback();
                errorlog << "其他异常: " << e.what();
                return false;
            }
        }
        bool query_user_follow(const std::string& follower,const std::string& following){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<UserFollowInfo>;
                using result = odb::result<UserFollowInfo>;
                result res(db->query<UserFollowInfo>(query::follower == follower && query::following == following));
                transa.commit();
                return !res.empty();
            } catch (const odb::exception& e) {
                transa.rollback();
                errorlog << "ODB异常: " << e.what();
                return false;
            } catch (const std::exception& e) {
                transa.rollback();
                errorlog << "其他异常: " << e.what();
                return false;
            }
        }
        bool delete_user_follow(const std::string& follower,const std::string& following){
            odb::transaction transa;
            try{
                transa.reset(db->begin());
                using query = odb::query<UserFollowInfo>;
                using result = odb::result<UserFollowInfo>;
                result res(db->query<UserFollowInfo>(query::follower == follower && query::following == following));
                auto it = res.begin();
                db->erase(*it);
                transa.commit();
                return true;
            } catch (const odb::exception& e) {
                errorlog << "ODB异常: " << e.what();
                transa.rollback();
                return false;
            } catch (const std::exception& e) {
                errorlog << "其他异常: " << e.what();
                transa.rollback();
                return false;
            }
        }

// ============================UserFollowerInfo-end============================

    };
}